﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace Utility
{
    public class StringFormatExt
    {
        private StringFormatExt()
        {

        }
        static StringFormatExt _instance = null;
        public static StringFormatExt S
        {
            get {
                if (_instance == null)
                {
                    _instance= new StringFormatExt();
                }
                return _instance;
            }
        }

        object __common_data_row;
        public  string StringFormatByData(string format, object obj)
        {
            if (obj is DataTable)
            {
                DataTable dtbl = (DataTable)obj;
                if (dtbl.Rows.Count > 0)
                {
                    obj = dtbl.Rows[0];
                }
                else
                {
                    throw new NullReferenceException("StringFormatByData: Argument[DataTable rows] not data");
                }
            }
            else if(!(obj is DataRow || obj is IDictionary))
            {
                Dictionary<string,object> dic = new Dictionary<string, object>();
                Type type = obj.GetType();
                foreach (PropertyInfo pi in type.GetProperties())
                {
                    if (pi.PropertyType.IsValueType || pi.PropertyType.Equals(typeof(string))
                         || pi.PropertyType.Equals(typeof(DateTime))) {
                        dic[pi.Name] = pi.GetValue(obj,null);
                    }
                }

                foreach (FieldInfo pi in type.GetFields())
                {
                    if (pi.FieldType.Equals(typeof(ValueType)) || pi.FieldType.Equals(typeof(string))
                         || pi.FieldType.Equals(typeof(DateTime)))
                    {
                        dic[pi.Name] = pi.GetValue(obj);
                    }
                }
                obj = dic;
            }
            
            Regex reg = new Regex(@"\{\s*(\w+)\s*}|\{\s*(\w+)\s*:*\s*([^{}]+)\s*\}");
            __common_data_row = obj;
            return reg.Replace(format, new MatchEvaluator(ReplaceStringFormatRegex));
        }

        private bool FieldIsNull(object data, string field_name)
        {
            if (data is DataRow)
            {
                DataRow dr = (DataRow)data;
                return dr.IsNull(field_name);
            }
            else if (data is IDictionary)
            {
                IDictionary d = (IDictionary)data;
                return d.Contains(field_name);
            }
            return false;
        }

        private object GetFieldValue(object data, string field_name)
        {
            if (data is DataRow)
            {
                DataRow dr = (DataRow)data;
                return dr[field_name];
            }
            else if (data is IDictionary)
            {
                IDictionary d = (IDictionary)data;
                return d[field_name];
            }
            return false;
        }

        private string ReplaceStringFormatRegex(Match m)
        {
            string empty = "";
            if (!m.Success)
            {
                return empty;
            }
            string field_name = m.Groups[1].Value;
            if (string.IsNullOrEmpty(field_name))
            {
                field_name = m.Groups[2].Value;
            }
            if (!FieldIsNull(__common_data_row,field_name))
            {
                return empty;
            }
            string format = "";
            if (m.Groups.Count > 3)
            {
                format = m.Groups[3].Value.Trim();
            }
            object obj = GetFieldValue(__common_data_row,field_name) ;
            if (obj == null)
            {
                return empty;
            }
            if (string.IsNullOrEmpty(format))
            {
                if (obj.GetType().Equals(typeof(DateTime)))
                {
                    format = "{0:yyyy-MM-dd}";
                    DateTime currentDate = (DateTime)obj;
                    if (currentDate <= DateTime.Parse("1900-01-30"))
                    {
                        format = "";
                    }
                }
                else if (obj.GetType().Equals(typeof(Decimal)))
                {
                    format = "{0:F2}";
                }
                else
                {
                    format = "{0}";
                }
            }
            else
            {
                format = "{0:" + format.Trim(':') + "}";
            }
            return string.Format(format, obj);
        }

    }
}
